#pragma once

#include "my_defs.h"
#include "my_atomic.h"

typedef my_atomic_int64_t           my_spinlock_t;

#define MY_SPINLOCK_INITLIZER       0

#define MY_LOCK_SPIN                5

static inline void
my_spinlock_init(my_spinlock_t *lock)
{
    my_atomic_int64_reset(lock);
}

static inline void
my_spinlock_lock(my_spinlock_t *lock)
{
    int64_t i = 0;
    for ( ;; ) {
        if (my_atomic_int64_cas(lock, 0, 1)) {
            return;
        }

        i++;
        if (i > MY_LOCK_SPIN) {
            MY_SCHED_YIELD;
        }
    }
}

static inline my_bool_t
my_spinlock_trylock(my_spinlock_t *lock) {
    int64_t i = 0;
    for ( ;; ) {
        if (my_atomic_int64_cas(lock, 0, 1)) {
            return MY_TRUE;
        }

        i++;
        if (i > MY_LOCK_SPIN) {
            return MY_FALSE;
        }
    }
}

static inline void
my_spinlock_unlock(my_spinlock_t *lock) {
    if (!my_atomic_int64_cas(lock, 1, 0)) {
        assert(!"unexcept state");
    }
}


typedef my_atomic_int64_t                       my_spin_wait_group_t;

#define MY_SPIN_WAIT_GROUP_INITLIZER            0

static inline void
my_spin_wait_group_init(my_spin_wait_group_t *wait_group)
{
    my_atomic_int64_reset(wait_group);
}

static inline void
my_spin_wait_group_add(my_spin_wait_group_t *wait_group, int64_t incr)
{
    my_atomic_int64_fetch_add(wait_group, incr);
}

static inline void
my_spin_wait_group_done(my_spin_wait_group_t *wait_group)
{
    my_atomic_int64_fetch_add(wait_group, -1);
}

static inline void
my_spin_wait_group_wait(my_spin_wait_group_t *wait_group)
{
    int64_t status;
    int64_t i = 0;
    for ( ;; ) {
        status = my_atomic_int64_load(wait_group);
        if (status == 0) {
            return;
        }

        if (status < 0) {
            assert(!"unexcept status");
        }

        i++;
        if (i > MY_LOCK_SPIN) {
            MY_SCHED_YIELD;
        }
    }
}